package com.gitee.deament.server.core;

import cn.hutool.core.util.ClassUtil;
import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.config.SystemProperties;
import com.gitee.deament.server.core.annotation.AnnoManageUtil;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.annotation.CliHanderScan;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.cli.CliContext;
import com.gitee.deament.server.core.data.DBData;
import com.gitee.deament.server.core.data.thread.ExpirKeyThread;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SkyCloudServer {
    static Logger logger = LoggerFactory.getLogger(SkyCloudServer.class);
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workGroup = new NioEventLoopGroup();

    public void startServer(Class<?> clazz) {


        try {
            logger.info("init cliContext");
            initCliContext(clazz);
            SystemProperties systemProperties = SystemConfig.SYSTEM_PROPERTIES;
            logger.info("init dbData");
            initDBData();

            logger.info("open the port localhost:"+systemProperties.getPort());
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class).handler(
                    new LoggingHandler(LogLevel.INFO))
                    .childHandler(new MyServerInitailizer());
            ChannelFuture channelFuture = serverBootstrap.bind(systemProperties.getPort()).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    /**
     * 启动命令上下文
     * @param clazz
     * @throws Exception
     */
    private void initCliContext(Class<?> clazz) throws  Exception{
        boolean hasScan = clazz.isAnnotationPresent(CliHanderScan.class);
        if (hasScan) {
            String[] packages = clazz.getAnnotation(CliHanderScan.class).packages();
            Class[] includeClasses = clazz.getAnnotation(CliHanderScan.class).include();
            Class[] excludeClasses = clazz.getAnnotation(CliHanderScan.class).exclude();
            logger.info("CliHanderScan.packages="+Arrays.stream(packages).collect(Collectors.toList()));
            List<Class> allClasses=new ArrayList<>(200);
            for(String pack:packages){

                allClasses.addAll(AnnoManageUtil.getPackageClass(pack, CliHander.class));
            }
            allClasses.addAll(Arrays.stream(includeClasses).collect(Collectors.toList()));
            allClasses.removeAll(Arrays.stream(excludeClasses).collect(Collectors.toList()));
            for(Class cla:allClasses){
                String command=   Class.forName(cla.getName()).getAnnotation(CliHander.class).command();
                CliContext.getCliList().put(command,(AbstractCli) Class.forName(cla.getName()).newInstance());
                logger.info("load command into CliContext:"+command);
            }
        }

    }

    private void initDBData(){
        DBData dbData = SystemConfig.dbData;
        dbData.init(SystemConfig.SYSTEM_PROPERTIES.getDbnum());
        //键值对过期线程
        ExpirKeyThread.start();
    }

}
